package com.geek.water.security;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

/**
 * @author chenmin
 * @desc TODO
 * @date 2025/8/11
 *
 * 自定义Security配置类
 * 1.开启Security认证  @EnableWebSecurity
 * 2.开启Security注解授权  @EnableGlobalMethodSecurity(prePostEnabled = true)
 * 3.extends WebSecurityConfigurerAdapter  + @Override  configure()
 *
 *
 * 认证
 * 1.开启Security认证  @EnableWebSecurity
 * 2.extends WebSecurityConfigurerAdapter  + @Override  configure()
 * 3.实现JwtAuthenticationTokenFilter过滤器，验证Token合法性
 * 4.实现自定义 UserDetailsService 登录业务逻辑 +  实现自定义 UserDetails 认证用户
 *
 * 授权
 * 1.开启Security注解授权  @EnableGlobalMethodSecurity(prePostEnabled = true)
 * 2.在接口中使用注解
 * 注解 @PreAuthorize("authentication.principal.username!='user'")  当前认证用户信息比对
 * 注解 @PreAuthorize("hasAnyRole('ROLE_ADMIN','ROLE_HEALTH_MANAGER')")  hasAnyRole  hasRole
 * 注解 @PreAuthorize("!hasAuthority('CHECKITEM_EDIT')")   hasAnyAuthority  hasAuthority
 */
//开启Security认证
@EnableWebSecurity
//开启Security注解授权
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Configuration
//@RequiredArgsConstructor
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    //401认证失败
    private final AuthenticationEntryPoint authenticationEntryPoint;
    //403授权失败
    private final AccessDeniedHandler accessDeniedHandler;
    //认证过滤器
    private final JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;
    //用户Mapper
    private final com.geek.water.mapper.UserMapper userMapper;
    //密码加密处理器
    private final BCryptPasswordEncoder passwordEncoder;

    public SecurityConfig(
            AuthenticationEntryPoint authenticationEntryPoint,
            AccessDeniedHandler accessDeniedHandler,
            RedisTemplate<String,Object> redisTemplate,
            BCryptPasswordEncoder passwordEncoder,
            com.geek.water.mapper.UserMapper userMapper){
        this.authenticationEntryPoint = authenticationEntryPoint;
        this.accessDeniedHandler = accessDeniedHandler;
        this.jwtAuthenticationTokenFilter = new JwtAuthenticationTokenFilter(redisTemplate);
        this.userMapper = userMapper;
        this.passwordEncoder = passwordEncoder;
    }

    //密码处理器
    /*@Bean
    public BCryptPasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }*/

    //配置密码编码器
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService())
                .passwordEncoder(passwordEncoder);
    }

    //配置UserDetailsService
    @Bean
    @Override
    public UserDetailsService userDetailsService() {
        return new SecurityUserDetailsService(userMapper);
    }

    //基于数据库认证&授权
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                //禁用csrf跨站攻击
                .csrf().disable()
                //解决跨域问题
                .cors()
                .and()
                //禁用session
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                //请求放行的资源
                .authorizeRequests().mvcMatchers("/admin/auth/login" , "/druid/**").permitAll()
                //任何请求都需要认证
                .anyRequest().authenticated();

        //401 403 异常处理器
        http.exceptionHandling()
                .accessDeniedHandler(accessDeniedHandler)   //403  授权失败
                .authenticationEntryPoint(authenticationEntryPoint);   //401 认证失败

        //认证授权过滤器
        http.addFilterBefore(jwtAuthenticationTokenFilter , UsernamePasswordAuthenticationFilter.class);
    }


    //通过@Bean将默认的认证管理器注册至IOC容器中
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    //对静态资源处理
    public static final String STATIC_PATH = "/swagger-ui.html,/doc.html,/webjars/**,/swagger-resources/**,/v2/**";
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().mvcMatchers(STATIC_PATH.split(","));
    }
}
